home *** CD-ROM | disk | FTP | other *** search
- /*
- * ScreenKeys - A small and simple screen hotkey commodity.
- *
- * Public domain in 1995 by Magnus Holmgren.
- *
- * Written using the DICE compiler - no startup code.
- *
- * #define OS3 to get a somewhat smaller, OS 3.0+-specific version.
- */
- #include <clib/alib_protos.h>
- #include <clib/commodities_protos.h>
- #include <clib/dos_protos.h>
- #include <clib/exec_protos.h>
- #include <clib/intuition_protos.h>
- #include <clib/icon_protos.h>
- #include <clib/utility_protos.h>
- #include <exec/alerts.h>
- #include <exec/execbase.h>
- #include <exec/memory.h>
- #include <intuition/intuitionbase.h>
- #include <workbench/startup.h>
- #include <string.h>
-
-
- #define VERSION "1.2"
-
-
- /******************** Global variables ********************/
-
-
- struct DosLibrary *DOSBase;
- struct Library *CxBase;
- struct Library *IconBase;
- struct IntuitionBase *IntuitionBase;
- struct ExecBase *SysBase;
- struct Library *UtilityBase;
-
- struct MsgPort *CxPort;
- struct WBStartup *WBMsg;
- CxObj *Broker;
-
- BOOL DoToBack;
-
-
- /******************** Startup code ********************/
-
-
- #ifdef OS3
- #define MINVER 39
- #else
- #define MINVER 37
- #endif
-
-
- LONG Main( VOID );
-
-
- __geta4 LONG
- Startup( VOID )
- {
- LONG r;
-
- SysBase = *( ( struct ExecBase ** ) 4 );
-
- {
- struct Process *thisTask = ( struct Process * ) FindTask( NULL );
-
- if( !thisTask->pr_CLI )
- {
- /* Handle Workbench startup message */
- struct MsgPort *port = &thisTask->pr_MsgPort;
-
- WaitPort( port );
- WBMsg = ( struct WBStartup * ) GetMsg( port );
- }
- }
-
- SetSignal( 0, SIGBREAKF_CTRL_C );
-
- if( SysBase->LibNode.lib_Version >= MINVER )
- {
- r = Main();
- }
- else
- {
- r = 100;
- }
-
- if( WBMsg )
- {
- Forbid();
- ReplyMsg( ( struct Message * ) WBMsg );
- }
-
- return( r );
- }
-
-
- /******************** String constants ********************/
-
-
- const TEXT Ver[] = "ScreenKeys " VERSION " (" __COMMODORE_DATE__ ")";
-
- /* No localization yet... Would be quite easy to add though */
- const TEXT MSG_ERRORTITLE[] = "ScreenKeys error";
- const TEXT MSG_QUIT_GAD[] = "Quit";
- const TEXT MSG_NO_MEM[] = "Not enough memory!";
- const TEXT MSG_NO_LIB[] = "Couldn't open %s\nversion %ld or higher!";
- const TEXT MSG_NO_PAT[] = "Couldn't parse pattern\n\"%s\"!";
- const TEXT MSG_NO_SCR[] = "No hotkeys specified!";
- const TEXT MSG_NO_ICON[] = "Couldn't open program icon!";
- const TEXT MSG_NO_BROKER[] = "Couldn't create broker!";
- const TEXT MSG_BAD_FILTER[] = "Bad input description:\n\"%s\"!";
- const TEXT MSG_NO_CLI[] = "Shell start not yet supported\n";
- const TEXT MSG_DESCRIPTION[] = "Provides hotkeys for screens";
-
-
-
- /******************** Pool support ********************/
-
-
- /* Note: For this to work with DICE, some assembler stubs are needed (basically
- * "converting" the '@' prefix generated by DICE, to the '_' prefix in pools.lib.
- * In the DMakeFile, this is handled by the miscsr.lib. Should be trivial to
- * fix, if needed. Or you could change the prototypes to stack arguments, and use
- * the Lib#? functions instead.
- */
- APTR AsmCreatePool( __D0 ULONG, __D1 ULONG, __D2 ULONG, __A6 struct ExecBase * );
- VOID AsmDeletePool( __A0 APTR, __A6 struct ExecBase * );
- APTR AsmAllocPooled( __A0 APTR, __D0 ULONG, __A6 struct ExecBase * );
- APTR AsmFreePooled( __A0 APTR, __A1 APTR, __D0 ULONG, __A6 struct ExecBase * );
-
-
- APTR MemoryPool;
-
-
- LONG
- InitPool( VOID )
- {
- #ifdef OS3
- return( ( LONG ) ( MemoryPool = CreatePool( MEMF_CLEAR | MEMF_PUBLIC, 2048, 1024 ) ) );
- #else
- return( ( LONG ) ( MemoryPool = AsmCreatePool( MEMF_CLEAR | MEMF_PUBLIC, 2048, 1024, SysBase ) ) );
- #endif
- }
-
-
- VOID
- FreePool( VOID )
- {
- if( MemoryPool )
- {
- #ifdef OS3
- DeletePool( MemoryPool );
- #else
- AsmDeletePool( MemoryPool, SysBase );
- #endif
- MemoryPool = NULL;
- }
- }
-
-
- APTR
- MemAlloc( ULONG size )
- {
- APTR *mem;
-
- size += 4;
-
- #ifdef OS3
- if( mem = AllocPooled( MemoryPool, size ) )
- #else
- if( mem = AsmAllocPooled( MemoryPool, size, SysBase ) )
- #endif
- {
- *( ( ( ULONG * ) mem )++ ) = size;
- }
-
- return( mem );
- }
-
-
- /* Not used at the moment */
- #ifdef MEM_FREE_NEEDED
- VOID
- MemFree( APTR mem )
- {
- if( mem )
- {
- ULONG size = *( --( ( ULONG * ) mem ) );
- #ifdef OS3
- FreePooled( MemoryPool, mem, size );
- #else
- AsmFreePooled( MemoryPool, mem, size, SysBase );
- #endif
- }
- }
- #endif
-
-
- /******************** Misc ********************/
-
-
- LONG
- MyRequest( STRPTR title, STRPTR body, STRPTR gads, ... )
- {
- struct EasyStruct es;
-
- es.es_StructSize = sizeof( es );
- es.es_Flags = 0;
- es.es_Title = title;
- es.es_TextFormat = body;
- es.es_GadgetFormat = gads;
- return( EasyRequestArgs( NULL, &es, NULL, &gads + 1 ) );
- }
-
-
- VOID
- ErrRequest( STRPTR body, ... )
- {
- MyRequest( MSG_ERRORTITLE, body, MSG_QUIT_GAD, &body + 1 );
- }
-
-
- VOID
- MemError( VOID )
- {
- ErrRequest( MSG_NO_MEM );
- }
-
-
- struct Library *
- OpenLib( STRPTR name, LONG ver )
- {
- struct Library *lib;
-
- if( !( lib = OpenLibrary( name, ver ) ) )
- {
- ErrRequest( MSG_NO_LIB, name, ver );
- }
-
- return( lib );
- }
-
-
- /******************** Argument parsing ********************/
-
-
- /* Convert string to caseless pattern. Shows error requesters. */
- STRPTR
- MakePattern( STRPTR str )
- {
- STRPTR pat;
- LONG len = strlen( str ) * 2 + 2;
-
- if( pat = MemAlloc( len ) )
- {
- if( ParsePatternNoCase( str, pat, len ) < 0 )
- {
- ErrRequest( MSG_NO_PAT, str );
- pat = NULL;
- }
- }
- else
- {
- MemError();
- }
-
- return( pat );
- }
-
-
- /* Make a hotkey for the specified screen. Screen will be used
- * as the id (!), which makes the Commodity message loop very simple.
- */
- CxObj *
- MakeHotKey( STRPTR hotkey, STRPTR screen )
- {
- CxObj *hot;
-
- if( hot = HotKey( hotkey, CxPort, ( LONG ) screen ) )
- {
- if( CxObjError( hot ) )
- {
- ErrRequest( MSG_BAD_FILTER, hotkey );
- DeleteCxObj( hot );
- hot = NULL;
- }
- }
- else
- {
- MemError();
- }
-
- return( hot );
- }
-
-
- /* Parse a SCREENKEY tooltype */
- BOOL
- ParseHotKey( CxObj *broker, STRPTR arg )
- {
- struct CSource in;
- TEXT buf[ 256 ];
- LONG i;
- BOOL ret = FALSE;
-
- in.CS_Buffer = arg;
- in.CS_Length = strlen( arg );
- in.CS_CurChr = 0;
-
- /* Maybe not used often, but it is quite handy.
- * Similar to strtok, but with quote support.
- */
- i = ReadItem( buf, sizeof( buf ), &in );
-
- if( ( i == ITEM_UNQUOTED ) || ( i == ITEM_QUOTED ) )
- {
- STRPTR screen;
- LONG i;
-
- #ifndef OS3
- /* Fix ParsePatternNoCase bug */
- for( screen = buf; *screen; ++screen )
- {
- *screen = ToUpper( *screen );
- }
- #endif
-
- screen = MakePattern( buf );
-
- while( ( i = ReadItem( buf, sizeof( buf ), &in ) ) == ITEM_EQUAL )
- {
- }
-
- if( screen && ( ( i == ITEM_UNQUOTED ) || ( i == ITEM_QUOTED ) ) )
- {
- CxObj *hotkey;
-
- if( hotkey = MakeHotKey( buf, screen ) )
- {
- AttachCxObj( broker, hotkey );
- ret = TRUE;
- }
- }
- }
-
- return( ret );
- }
-
-
- /* Get the CX_PRIORITY value */
- LONG
- GetCxPri( struct DiskObject *icon )
- {
- STRPTR str;
- LONG val = 0;
-
- if( str = FindToolType( icon->do_ToolTypes, "CX_PRIORITY" ) )
- {
- StrToLong( str, &val );
- }
-
- return( val );
- }
-
-
- /* Add hotkeys for the screens to the broker */
- BOOL
- AddHotKeys( CxObj *broker, struct DiskObject *icon )
- {
- STRPTR *args;
- BOOL err = FALSE, keys = FALSE;
-
- SetIoErr( 0 );
-
- for( args = icon->do_ToolTypes; *args; ++args )
- {
- if( !Strnicmp( "SCREENKEY=", *args, 10 ) )
- {
- if( !ParseHotKey( broker, *args + 10 ) )
- {
- err = TRUE;
- break;
- }
- else
- {
- keys = TRUE;
- }
- }
- }
-
- if( !( err || keys ) )
- {
- ErrRequest( MSG_NO_SCR );
- return( FALSE );
- }
- else
- {
- return( !err );
- }
- }
-
-
- /******************** Commodity support ********************/
-
-
- struct NewBroker NewBroker =
- {
- NB_VERSION,
- "ScreenKeys",
- "ScreenKeys "VERSION,
- MSG_DESCRIPTION,
- NBU_UNIQUE, 0, 0,
- NULL, 0
- };
-
-
- VOID
- FreeBroker( VOID )
- {
- DeleteCxObjAll( Broker );
- DeleteMsgPort( CxPort );
- }
-
-
- BOOL
- InitBroker( VOID )
- {
- BOOL ret = FALSE;
-
- if( IconBase = OpenLib( "icon.library", 37 ) )
- {
- struct DiskObject *icon;
- BPTR oldDir;
-
- oldDir = CurrentDir( WBMsg->sm_ArgList[ 0 ].wa_Lock );
-
- if( icon = GetDiskObject( WBMsg->sm_ArgList[ 0 ].wa_Name ) )
- {
- NewBroker.nb_Pri = GetCxPri( icon );
- DoToBack = ( BOOL ) FindToolType( icon->do_ToolTypes, "SCREENTOBACK" );
-
- if( CxPort = NewBroker.nb_Port = CreateMsgPort() )
- {
- LONG err;
-
- if( Broker = CxBroker( &NewBroker, &err ) )
- {
- ret = AddHotKeys( Broker, icon );
- }
- else if( err != CBERR_DUP )
- {
- ErrRequest( MSG_NO_BROKER );
- }
- }
-
- FreeDiskObject( icon );
- }
- else
- {
- ErrRequest( MSG_NO_ICON );
- }
-
- CurrentDir( oldDir );
- CloseLibrary( IconBase );
- }
-
- if( !ret )
- {
- FreeBroker();
- }
-
- return( ret );
- }
-
-
- VOID
- HandleHotKey( STRPTR screen )
- {
- struct Screen *scr, *front;
- ULONG lock = LockIBase( 0 );
-
- if( front = IntuitionBase->FirstScreen )
- {
- for( scr = front->NextScreen; scr; scr = scr->NextScreen )
- {
- if( scr->Title && MatchPatternNoCase( screen, scr->Title ) )
- {
- /* So screen won't close "beneath" us */
- Forbid();
- UnlockIBase( lock );
- ScreenToFront( scr );
-
- if( DoToBack )
- {
- /* So cycling works as intended */
- ScreenToBack( front );
- }
-
- Permit();
- return;
- }
- }
- }
-
- UnlockIBase( lock );
- }
-
-
- BOOL
- HandleCxPort( VOID )
- {
- CxMsg *msg;
- BOOL run = TRUE;
-
- while( msg = ( CxMsg * ) GetMsg( CxPort ) )
- {
- LONG id, type;
-
- id = CxMsgID( msg );
- type = CxMsgType( msg );
- ReplyMsg( ( struct Message * ) msg );
-
- switch( type )
- {
- case CXM_IEVENT:
- HandleHotKey( ( STRPTR ) id );
- break;
-
- case CXM_COMMAND:
- switch( id )
- {
- case CXCMD_DISABLE:
- ActivateCxObj( Broker, FALSE );
- break;
-
- case CXCMD_ENABLE:
- ActivateCxObj( Broker, TRUE );
- break;
-
- case CXCMD_KILL:
- run = FALSE;
- break;
- }
-
- break;
- }
- }
-
- return( run );
- }
-
-
- /******************** Main program ********************/
-
-
- VOID
- MainLoop( VOID )
- {
- LONG cxMask = 1 << CxPort->mp_SigBit;
- BOOL run = TRUE;
-
- ActivateCxObj( Broker, TRUE );
-
- while( run )
- {
- LONG sigs;
-
- sigs = Wait( cxMask | SIGBREAKF_CTRL_C );
-
- if( sigs & cxMask )
- {
- if( !HandleCxPort() )
- {
- run = FALSE;
- }
- }
-
- if( sigs & SIGBREAKF_CTRL_C )
- {
- run = FALSE;
- }
- }
- }
-
-
- LONG
- Main( VOID )
- {
- LONG ret = RETURN_FAIL;
-
- if( DOSBase = ( struct DosLibrary * ) OpenLibrary( "dos.library", 37 ) )
- {
- if( WBMsg )
- {
- if( IntuitionBase = ( struct IntuitionBase * ) OpenLibrary( "intuition.library", 37 ) )
- {
- if( UtilityBase = OpenLib( "utility.library", 37 ) )
- {
- if( CxBase = OpenLib( "commodities.library", 37 ) )
- {
- if( InitPool() )
- {
- if( InitBroker() )
- {
- MainLoop();
- FreeBroker();
- }
-
- FreePool();
- }
- else
- {
- MemError();
- }
-
- CloseLibrary( CxBase );
- }
-
- CloseLibrary( UtilityBase );
- }
-
- CloseLibrary( ( struct Library * ) IntuitionBase );
- }
- else
- {
- Alert( AT_Recovery | AN_Unknown | AG_OpenLib | AO_Intuition );
- }
- }
- else
- {
- PutStr( MSG_NO_CLI );
- }
-
- CloseLibrary( ( struct Library * ) DOSBase );
- }
- else
- {
- Alert( AT_Recovery | AN_Unknown | AG_OpenLib | AO_DOSLib );
- }
-
- return( ret );
- }
-